/*
 * COPYRIGHT Ericpol Telecom sp. z o.o. 2006
 * The copyright to the computer program(s) herein is the property of
 * Ericpol Telecom. The programs may be used and/or copied only with written
 * permission from Ericpol Telecom or in accordance with the terms and
 * conditions stipulated in the agreement under which the
 * programs have been supplied.
 *
 * $Id: SocketServerAppender.java 655 2007-06-26 13:00:31Z jacek.kolezynski $
 */
package logmatcher.appenders;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;

import java.io.IOException;
import java.io.ObjectOutputStream;

import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;


/**
*  Class Log4jXWayAppender is a custom Log4J appender that sends Log4J events to __Logger from XWay.     example:
*  Logger logger = Logger.getRootLogger(); Log4jXWayAppender log4japp = new Log4jXWayAppender();
*  logger.addAppender(log4japp);
 */
public class SocketServerAppender extends AppenderSkeleton implements Runnable {
    //~ Instance fields ------------------------------------------------------------------------------------------------

    /** Class logger. */
    private final Log LOGGER = LogFactory.getLog(SocketServerAppender.class);

    /** Server socket instance. */
    private ServerSocket serverSocket;

    /** TODO: DOCUMENT ME! */
    private Socket socket;

    /** Working thread, carrying out listening to new connections. */
    private Thread worker = new Thread(this);

    /** TODO: DOCUMENT ME! */
    private int portNumber = 7788;

    /** TODO: DOCUMENT ME! */
    private ObjectOutputStream outputStream;

    /** TODO: DOCUMENT ME! */
    private boolean connectionEstablished;

    //~ Constructors ---------------------------------------------------------------------------------------------------

/**
     *  Creates a new SocketServerAppender object.
    */
    public SocketServerAppender() {
       startServer();
    }
    
    private void startServer(){
    	 try {
             System.out.println(">>>>>>> Creating ServerSocket on port "+ portNumber+"...");
             serverSocket = new ServerSocket(portNumber);

             closed = false;
             worker.start();
         } catch (IOException e) {
        	 System.out.println(">>>>>>> Port is not free, trying next one...");
        	 
        	 portNumber ++;
        	 startServer();
         }
    }

    //~ Methods --------------------------------------------------------------------------------------------------------

    /**
    *  Log event happened. Translates level to status instance codes:  Level.FATAL_INT - Critical level
    *  Level.ERROR_INT - Error level  Level.WARN_INT - Warning level  Level.DEBUG_INT - Debug level  Level.INFO_INT -
    *  Info
    *
    *  @param event LoggingEvent instance
    */
    public void append(LoggingEvent event) {
        if (closed) {
            return;
        }

        if (!connectionEstablished) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Connection is not established yet, ignoring message");
            }
        } else {
            String message = String.valueOf(event.getMessage());

            try {
                outputStream.writeObject(message);
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
    *  Closes this appender.
    */
    public void close() {
        this.closed = true;
    }


    /**
    *  Checks if this appender requires layout.
    *
    *  @return true if layout is required.
    */
    public boolean requiresLayout() {
        return false;
    }


    /**
    *  
    *  @see Runnable#run()
    */
    public void run() {
        while (!closed) {
            try {
                socket = serverSocket.accept();
                outputStream = new ObjectOutputStream(socket.getOutputStream());
                connectionEstablished = true;
                LOGGER.info("Connection to appender established");
            } catch (SocketException e) {
                connectionEstablished = false;
                LOGGER.info("Socket closed");

                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Socket suspected to be closed", e);
                }
            } catch (IOException e) {
                LOGGER.error("Error while establishing a connection", e);
                connectionEstablished = false;
            }
        }
    }
}
